package com.sjr.easy.chat.app.controller;

import com.alibaba.fastjson2.JSON;
import com.sjr.easy.chat.app.EasyChatAppConfig;
import com.sjr.easy.chat.app.constants.UserHeadPortraitStoreTypeEnum;
import com.sjr.easy.chat.app.dto.AppTokenInfo;
import com.sjr.easy.chat.app.enums.AppLoginStatusEnum;
import com.sjr.easy.chat.app.utils.AppTokenManager;
import com.sjr.easy.chat.app.utils.AppTokenUtils;
import com.sjr.easy.chat.app.utils.SequenceUtils;
import com.sjr.easy.chat.dto.Result;
import com.sjr.easy.chat.model.User;
import com.sjr.easy.chat.service.UserService;
import com.sjr.easy.chat.utils.SHA256;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import jakarta.servlet.http.HttpServletRequest;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.file.PathUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.file.Path;
import java.util.Date;
import java.util.Objects;

@Slf4j
@RestController
@Api("App用户相关Rest接口")
public class AppUserController {

    @Autowired
    private UserService userService;

    @Autowired
    private AppTokenManager appTokenManager;

    @Autowired
    private SequenceUtils sequenceUtils;

    @Autowired
    private EasyChatAppConfig easyChatAppConfig;

    @Data
    public static class AppLoginReq {
        private String phone;
        private String password;
    }

    @PostMapping("/app/user/login")
    public Result<String> login(@RequestBody AppLoginReq appLoginReq) {

        User user = userService.selectByPhone(appLoginReq.phone);
        log.info("user:{}", JSON.toJSONString(user));
        if (user == null) {
            log.info("用户不存在");
            return Result.error("用户不存在");
        }
        String hashedPassword = passwordHash(appLoginReq.password, user.getPasswordSalt());
        log.info("hashedPassword:{}", hashedPassword);
        if (!StringUtils.equals(hashedPassword, user.getPassword())) {
            log.error("密码错误");
            return Result.error("密码错误");
        }

        AppTokenInfo appTokenInfo = new AppTokenInfo();
        appTokenInfo.setId(user.getId());
        appTokenInfo.setNickName(user.getNickname());
        appTokenInfo.setPhone(user.getPhone());
        appTokenInfo.setLoginTime(System.currentTimeMillis());

        String token = AppTokenUtils.generateToken(appTokenInfo);
        appTokenManager.setToken(token, appTokenInfo);
        return Result.success(token);
    }


    @Data
    public static class AppRegisterReq {
        private String phone;
        private String password;
    }

    @PostMapping("/app/user/register")
    public Result<String> register(@RequestBody AppRegisterReq appRegisterReq) {

        Assert.hasLength(appRegisterReq.getPhone(), "手机号不允许为空");
        Assert.hasLength(appRegisterReq.getPassword(), "密码不允许为空");

        String passwordSalt = String.valueOf(System.currentTimeMillis());
        Long userCode = sequenceUtils.genUserCode();
        Objects.requireNonNull(userCode, "用户Code生成错误");
        User user = new User();
        user.setCode(userCode.toString());
        user.setNickname(appRegisterReq.getPhone());
        user.setPhone(appRegisterReq.phone);
        user.setPasswordSalt(passwordSalt);
        user.setPassword(passwordHash(appRegisterReq.password, passwordSalt));
        userService.addUser(user);

        AppLoginReq appLoginReq = new AppLoginReq();
        appLoginReq.phone = appRegisterReq.phone;
        appLoginReq.password = appRegisterReq.password;
        return login(appLoginReq);
    }


    private String passwordHash(String password, String passwordSalt) {
        return SHA256.cryptToHexString(String.format("password=%s&passwordSalt=%s", password, passwordSalt));
    }


    @PostMapping("/app/user/logout")
    public Result<Object> logout(@RequestHeader("token") String token) {
        log.info("token:{}", token);
        appTokenManager.removeToken(token);
        return Result.success();
    }

    @GetMapping("/app/user/getLoginUserInfo")
    public Result<AppTokenInfo> getLoginUserInfo(HttpServletRequest request) {
        String token = request.getHeader("token");
        AppTokenInfo tokenInfo = appTokenManager.getTokenInfo(token);
        log.info("tokenInfo:{}", JSON.toJSONString(tokenInfo));
        if (tokenInfo == null) {
            return Result.error(AppLoginStatusEnum.TokenTimeout.getCode(), AppLoginStatusEnum.TokenTimeout.getMessage());
        }
        return Result.success(tokenInfo);
    }

    @Data
    static class AppUserDetail {

        @ApiModelProperty("")
        private Long id;

        @ApiModelProperty("用户编号")
        private String code;

        @ApiModelProperty("昵称")
        private String nickname;

        @ApiModelProperty("手机号")
        private String phone;

        @ApiModelProperty("用户头像")
        private String headPortrait;

        @ApiModelProperty("用户头像存储类型：http存储类型可以直接加载、local类型需要通过指定接口加载图片")
        private String headPortraitStoreType;
    }

    @ApiOperation("查询用户信息详情")
    @GetMapping("/app/user/getAppUserDetail")
    public Result<AppUserDetail> getAppUserDetail(@RequestHeader("token") String token) {
        AppTokenInfo tokenInfo = appTokenManager.getTokenInfo(token);
        log.info("tokenInfo:{}", JSON.toJSONString(tokenInfo));
        User user = userService.selectById(tokenInfo.getId());
        if (user == null) {
            return Result.error("用户不存在");
        }
        AppUserDetail appUserDetail = new AppUserDetail();
        BeanUtils.copyProperties(user, appUserDetail);
        return Result.success(appUserDetail);
    }


    @Data
    static class GetUserPublicInfoByCodeResultData {

        @ApiModelProperty("")
        private Long id;

        @ApiModelProperty("用户编号")
        private String code;

        @ApiModelProperty("昵称")
        private String nickname;

        @ApiModelProperty("用户头像")
        private String headPortrait;

        @ApiModelProperty("用户头像存储类型：http存储类型可以直接加载、local类型需要通过指定接口加载图片")
        private String headPortraitStoreType;
    }

    @ApiOperation("查询用户公开信息")
    @GetMapping("/app/user/getUserPublicInfoByCode")
    public Result<GetUserPublicInfoByCodeResultData> getUserPublicInfoByCode(@RequestParam String code) {
        log.info("code:{}", code);
        User user = userService.selectByCode(code);
        if (user == null) {
            return Result.error("用户不存在");
        }
        GetUserPublicInfoByCodeResultData resultData = new GetUserPublicInfoByCodeResultData();
        BeanUtils.copyProperties(user, resultData);
        return Result.success(resultData);
    }

    @Data
    static class UploadUserHeadPortraitResultData {

        @ApiModelProperty("用户头像")
        private String headPortrait;

        @ApiModelProperty("")
        private String headPortraitStoreType;
    }

    @ApiOperation("上传用户头像")
    @PostMapping("/app/user/uploadUserHeadPortrait")
    public Result<UploadUserHeadPortraitResultData> uploadUserHeadPortrait(MultipartFile file) throws IOException {

        AppTokenInfo tokenInfo = appTokenManager.getTokenInfo();
        log.info("tokenInfo:{}", JSON.toJSONString(tokenInfo));
        User user = userService.selectById(tokenInfo.getId());
        if (user == null) {
            return Result.error("用户不存在");
        }

        // 生成文件名（无后缀）
        Long userPortraitName = sequenceUtils.genUserPortraitName();
        // 文件存储目录
        String baseFilePath = easyChatAppConfig.getUserHeadPortraitStorePath();
        if (!baseFilePath.endsWith("/")) {
            baseFilePath += "/";
        }

        // 文件扩展名
        String fileNameExtension = "";
        if (StringUtils.isNotEmpty(file.getOriginalFilename()) && file.getOriginalFilename().contains(".")) {
            fileNameExtension = file.getOriginalFilename().substring(file.getOriginalFilename().indexOf("."));
        }
        // 文件保存名称
        String targetFileName = userPortraitName + fileNameExtension;

        // 文件存储相对路径
        String relativeTargetFilePath = DateFormatUtils.ISO_8601_EXTENDED_DATE_FORMAT.format(new Date()) + "/" + targetFileName;
        // 文件存储绝对路径
        String targetFilePath = baseFilePath + relativeTargetFilePath;
        PathUtils.createParentDirectories(Path.of(targetFilePath));
        file.transferTo(Path.of(targetFilePath));

        User userParams = new User();
        userParams.setId(user.getId());
        userParams.setHeadPortrait(relativeTargetFilePath);
        userParams.setHeadPortraitStoreType(UserHeadPortraitStoreTypeEnum.local.getCode());
        userService.updateUserHeadPortrait(userParams);

        UploadUserHeadPortraitResultData uploadUserHeadPortraitResultData = new UploadUserHeadPortraitResultData();
        BeanUtils.copyProperties(userParams, uploadUserHeadPortraitResultData);
        return Result.success(uploadUserHeadPortraitResultData);
    }

    @Data
    static class ChangeUserNickNameReqParams {
        @ApiModelProperty("新的用户昵称")
        public String newNickName;
    }

    @ApiOperation("修改用户昵称")
    @PostMapping("/app/user/changeUserNickName")
    public Result<Object> changeUserNickName(@RequestBody ChangeUserNickNameReqParams reqParams) {
        reqParams.newNickName = StringUtils.trim(reqParams.newNickName);
        log.info("reqParams:{}", JSON.toJSONString(reqParams));
        if (reqParams.newNickName == null || StringUtils.isEmpty(reqParams.newNickName)) {
            return Result.error("用户昵称不允许为空");
        }
        AppTokenInfo tokenInfo = appTokenManager.getTokenInfo();
        log.info("tokenInfo:{}", JSON.toJSONString(tokenInfo));

        userService.changeUserNickName(tokenInfo.getId(), reqParams.newNickName);

        return Result.success();
    }

}
